/*
 * $Author: cbeams $
 * $Date: 2007-06-04 19:47:27 +0000 (Mon, 04 Jun 2007) $
 * $Rev: 26 $
 */
package com.db4o.eclipse.plugin.views;

import com.db4o.eclipse.plugin.model.Db4oStoredClass;
import com.db4o.eclipse.plugin.model.Db4oStoredObjectInstance;

import com.db4o.reflect.ReflectField;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.*;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import org.eclipse.ui.*;
import org.eclipse.ui.part.*;

import static java.lang.String.format;


/**
 * This sample class demonstrates how to plug-in a new workbench view. The view shows data obtained
 * from the model. The sample creates a dummy model on the fly, but a real implementation would
 * connect to the model available either in this or another plug-in (e.g. the workspace). The view
 * is connected to the model using a content provider.
 *
 * <p>The view uses a label provider to define how model objects should be presented in the view.
 * Each view can present the same model objects using different labels and icons, if needed.
 * Alternatively, a single label provider can be shared between views in order to ensure that
 * objects of the same type are presented in the same way everywhere.</p>
 */

public class StoredObjectsView extends ViewPart {
    public static final String ID = StoredObjectsView.class.getName();
    private TableViewer viewer;
    private ISelectionListener pageSelectionListener;

    /** The constructor. */
    public StoredObjectsView() {}

    /**
     * This is a callback that will allow us to create the viewer and initialize it.
     *
     * @param  parent  TODO: DOCUMENT ME!
     */
    @Override
    public void createPartControl(Composite parent) {
        viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
        viewer.setContentProvider(new ViewContentProvider());
        viewer.setLabelProvider(new ViewLabelProvider());
        viewer.setInput(getViewSite());
        hookPageSelection();
        setContentDescription("");
        initTable();

    }

    private void initTable() {
        Table table = viewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);
    }

    private void hookPageSelection() {
        pageSelectionListener =
            new ISelectionListener() {
                public void selectionChanged(IWorkbenchPart part, ISelection selection) {
                    pageSelectionChanged(part, selection);
                }
            };

        getSite().getPage().addPostSelectionListener(pageSelectionListener);
    }

    private void pageSelectionChanged(IWorkbenchPart part, ISelection selection) {

        // we only care about selection changes that happen in the Explorer View
        if (!(part instanceof Db4oExplorerView))
            return;

        // if the user clicks on whitespace or focuses the Explorer View, we may get an 'empty
        // selection' event. Discard it.
        if (selection.isEmpty())
            return;

        // there should be no other type of selection coming in, but lets be sure.
        if (!(selection instanceof IStructuredSelection))
            return;

        // The Explorer View is configured such that it allows only single selections (SWT.SINGLE
        // vs SWT.MULTI).  Because of this, we can simply call the getFirstElement() method off the
        // selection rather than looping through it's iterator.
        IStructuredSelection structuredSelection = (IStructuredSelection) selection;
        Object selectedObject = structuredSelection.getFirstElement();

        if (!(selectedObject instanceof Db4oStoredClass))
            return;

        Db4oStoredClass db4oStoredClass = (Db4oStoredClass) selectedObject;

        this.updateContentDescription(db4oStoredClass);

        ReflectField[] fields = db4oStoredClass.getReflectClass().getDeclaredFields();

        // int[] columnWidths = new int[] { 100, 100, 35, 75 };
        // int[] columnAlignments = new int[] { SWT.LEFT, SWT.LEFT, SWT.CENTER, SWT.CENTER };

        Table table = viewer.getTable();

        // remove all the columns before we load a new class
        for (TableColumn column : table.getColumns())
            column.dispose();

        for (ReflectField field : fields) {
            field.setAccessible();
            TableColumn tableColumn = new TableColumn(table, SWT.LEFT);
            tableColumn.setText(field.getName());
            tableColumn.pack();
        }

        viewer.setLabelProvider(new StoredObjectTableLabelProvider());
        viewer.setContentProvider(new ArrayContentProvider());
        viewer.setInput(db4oStoredClass.getChildren());
    }

    private void updateContentDescription(Db4oStoredClass db4oStoredClass) {
        this.setContentDescription(format("Displaying objects of type: %s.  Instance count: %d",
                                          db4oStoredClass, 42));
    }

    @Override
    public void dispose() {
        super.dispose();
        if (pageSelectionListener != null)
            getSite().getPage().removePostSelectionListener(pageSelectionListener);
    }

    @SuppressWarnings("unused")
    private void showMessage(String message) {
        MessageDialog.openInformation(viewer.getControl().getShell(),
                                      "Db4o Objects",
                                      message);
    }

    /** Passing the focus request to the viewer's control. */
    @Override
    public void setFocus() {
        viewer.getControl().setFocus();
    }

    class StoredObjectTableLabelProvider extends LabelProvider implements ITableLabelProvider {

        public Image getColumnImage(Object element, int columnIndex) {
            return null;
        }

        public String getColumnText(Object element, int columnIndex) {
            if (!(element instanceof Db4oStoredObjectInstance))
                return element.toString();

            Db4oStoredObjectInstance storedObject = (Db4oStoredObjectInstance) element;
            ReflectField[] fields =
                storedObject.getDb4oStoredClass().getReflectClass().getDeclaredFields();

            // since our table's columns have been rendered out in order of this class's fields,
            // we can address the fields array by the columnIndex and know that we're going to
            // populate the right cell.
            ReflectField targetField = fields[columnIndex];
            targetField.setAccessible();
            return targetField.get(storedObject).toString();
        }

    }


    /*
     * The content provider class is responsible for
     * providing objects to the view. It can wrap
     * existing objects in adapters or simply return
     * objects as-is. These objects may be sensitive
     * to the current input of the view, or ignore
     * it and always show the same content
     * (like Task List, for example).
     */

    class ViewContentProvider implements IStructuredContentProvider {
        public void inputChanged(Viewer v, Object oldInput, Object newInput) {}

        public void dispose() {}

        public Object[] getElements(Object parent) {
            return new String[] { "One", "Two", "Three" };
        }
    }


    class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
        public String getColumnText(Object obj, int index) {
            return getText(obj);
        }

        public Image getColumnImage(Object obj, int index) {
            return getImage(obj);
        }

        @Override
        public Image getImage(Object obj) {
            return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
        }
    }
}
